package com.bubblegumproject.ogo.remote.http;

import com.bubblegumproject.ogo.action.Reactor;
import com.bubblegumproject.ogo.action.Action;
import com.bubblegumproject.ogo.remote.OgoRemoteException;
import com.bubblegumproject.ogo.remote.RemoteClient;
import com.sun.net.httpserver.HttpServer;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpExchange;
import org.apache.log4j.Logger;

import java.net.InetSocketAddress;
import java.io.IOException;

/**
 * Exports a <code>Reactor</code> to be available via HTTP.
 * 
 * @author Azubuko Obele (buko.obele@gmail.com)
 */
public class HttpExporter {

    private Reactor reactor;

    private String reactorName;

    private InetSocketAddress hostAddress;

    private HttpServer httpServer;

    private HttpRequestParser requestParser;

    private static final Logger log = Logger.getLogger(HttpExporter.class);

    public HttpExporter(Reactor reactor, String reactorName, InetSocketAddress hostAddress,
                        HttpRequestParser requestParser) {
        if (reactor == null || reactorName == null || hostAddress == null || requestParser == null)
            throw new IllegalArgumentException("null");
        this.reactor = reactor;
        this.reactorName = reactorName;
        this.hostAddress = hostAddress;
        this.requestParser = requestParser;
    }

    public void start() {
        try {
            httpServer = HttpServer.create(hostAddress, 25);
            String contextPath = "/" + reactorName;
            httpServer.createContext(contextPath, new ReactorHttpHandler());
            httpServer.start();
            log.info(this + " started context " + contextPath + " on " + hostAddress + " for reactor " + reactor);
        } catch (IOException ioe) {
            throw new OgoRemoteException(this + " failed to start http server", ioe);
        }
    }

    public void stop() {
        httpServer.stop(30);
        log.info(this + " stopped http server " + hostAddress + " for reactor " + reactor);
    }

    private class ReactorHttpHandler implements HttpHandler {
        public void handle(HttpExchange httpExchange) throws IOException {
            try {
                log.debug(this + " handling HTTP request " + httpExchange.getRequestURI());
                Action action = requestParser.parse(httpExchange);
                RemoteClient client = new HttpRemoteClient(httpExchange);
                log.debug(this + " processing action=" + action + " action.context=" + action.getContext());
                action.getContext().set(RemoteClient.class.getName(), client);
                reactor.react(action);
            } catch (Throwable t) {
                log.warn(this + " encountered error while processing request " + httpExchange.getRequestURI(), t);
            }
        }
    }
}
